<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebRTC 音视频播放</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            text-align: center;
            margin-top: 50px;
        }
        video {
            width: 640px;
            height: 360px;
            background: black;
        }
    </style>
</head>
<body>
    <h1>WebRTC 音视频播放</h1>
    <button onclick="startPlayback()">播放音视频</button>
    <br><br>
    <video id="video" autoplay playsinline controls></video>

    <script>
        let ws;
        let peerConnection;

        async function startPlayback() {
            console.log("Starting video and audio playback");
            console.log("Connecting to WebSocket at ws://localhost:8080/ws");
            ws = new WebSocket("ws://localhost:8080/ws");
            ws.onopen = () => console.log("WebSocket connection established");
            ws.onerror = (error) => console.error("WebSocket error:", error);
            ws.onclose = () => console.log("WebSocket connection closed");
            ws.onmessage = handleMessage;

            console.log("Creating RTCPeerConnection");
            peerConnection = new RTCPeerConnection({
                iceServers: [
                    { urls: "stun:stun.l.google.com:19302" },
                ]
            });

            peerConnection.onicecandidate = (event) => {
                if (event.candidate) {
                    console.log("New ICE candidate:", event.candidate.candidate);
                    ws.send(JSON.stringify({
                        type: "candidate",
                        candidate: JSON.stringify(event.candidate.toJSON())
                    }));
                    console.log("Sent ICE candidate to server");
                } else {
                    console.log("ICE candidate gathering complete");
                }
            };

            peerConnection.oniceconnectionstatechange = () => {
                console.log("ICE connection state:", peerConnection.iceConnectionState);
                if (peerConnection.iceConnectionState === "failed") {
                    console.log("ICE connection failed, restarting playback");
                    peerConnection.close();
                    startPlayback();
                }
            };

            peerConnection.ontrack = (event) => {
                console.log("Received track:", event.track.kind, event.track.id);
                console.log("Stream:", event.streams[0]);
                const video = document.getElementById("video");
                video.srcObject = event.streams[0];
                console.log("Set stream to video element");
            };

            const video = document.getElementById("video");
            video.onerror = () => console.error("Video element error:", video.error);
            video.oncanplay = () => console.log("Video can play");
            video.onplaying = () => console.log("Video and audio are playing");
            video.onwaiting = () => console.log("Video is waiting for data (buffering)");
            video.onstalled = () => console.log("Video stalled");

            setInterval(() => {
                if (video.buffered.length > 0) {
                    console.log("Buffered ranges:", video.buffered.start(0), "-", video.buffered.end(0));
                    console.log("Current time:", video.currentTime);
                }
                console.log("Video resolution:", video.videoWidth, "x", video.videoHeight);
            }, 5000);

            console.log("Creating offer");
            try {
                const offer = await peerConnection.createOffer({
                    offerToReceiveVideo: true,
                    offerToReceiveAudio: true
                });
                console.log("Offer created:", offer.sdp.substring(0, 200) + "...");
                await peerConnection.setLocalDescription(offer);
                console.log("Set local description");

                const sdp = btoa(peerConnection.localDescription.sdp);
                ws.send(JSON.stringify({
                    sdp: sdp,
                    type: "offer"
                }));
                console.log("Sent offer to server");
            } catch (error) {
                console.error("Error creating offer:", error);
            }
        }

        function handleMessage(event) {
            console.log("Received WebSocket message:", event.data);
            try {
                const signal = JSON.parse(event.data);
                switch (signal.type) {
                    case "answer":
                        console.log("Received answer from server");
                        const sdp = atob(signal.sdp);
                        console.log("Answer SDP:", sdp.substring(0, 200) + "...");
                        peerConnection.setRemoteDescription({
                            type: "answer",
                            sdp: sdp
                        }).then(() => {
                            console.log("Set remote description successfully");
                        }).catch(err => {
                            console.error("Set remote description error:", err);
                        });
                        break;
                    case "candidate":
                        console.log("Received ICE candidate from server");
                        try {
                            const candidate = JSON.parse(signal.candidate);
                            peerConnection.addIceCandidate(new RTCIceCandidate(candidate))
                                .then(() => console.log("Added ICE candidate successfully"))
                                .catch(err => console.error("Add ICE candidate error:", err));
                        } catch (err) {
                            console.error("Error parsing ICE candidate:", err);
                        }
                        break;
                    case "error":
                        console.log("Received error from server:", signal.sdp);
                        console.log("Restarting playback due to server error");
                        peerConnection.close();
                        startPlayback();
                        break;
                    default:
                        console.log("Unknown message type:", signal.type);
                }
            } catch (error) {
                console.error("Error parsing WebSocket message:", error);
            }
        }
    </script>
</body>
</html>